/*
2GWVS a free web vulnerability scanner.
Copyright (C) 2008  Grigis Gaetan

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

#include "issuesExecuter.h"
#include "formCatched.h"
#include <QDebug>

QList<issuesExecuter*> *issuesExecuter::allExecutedIssues=new QList<issuesExecuter*>;
int issuesExecuter::currentExecutedIssues=-1;

issuesExecuter::~issuesExecuter(){http->abort();delete http;}
issuesExecuter::issuesExecuter(int u,int i,int m) : QObject() {
	base_url=u;
	id_issue=i;
	status=0;
        current_parameter=0;
        method = m;
        if(method==0)
            current_url=UrlCatched::allUrl->at(base_url)->getUrl();
        if(method==1)
        {
            current_form=FormCatched::allForm->at(base_url);
            current_url =current_form->getUrl();
        }
	modified_url=QUrl();
        modified_url.setUrl(current_url.toString());
	testedFile=current_url.path();
	//testedParam set later
	allExecutedIssues->append(this);
}

void issuesExecuter::execute() {
    if(currentExecutedIssues>allExecutedIssues->count())
    {
        runScanner::setLog("Scan ended successufly \n");
        return;
    }

    if(!UrlCatched::allUrl->at(base_url)->UrlRewriting())
    {//here execution with QHttp object
        http=new QHttp(this);
        connect(http,SIGNAL(done(bool)),this,SLOT(getExecution()));

        if(current_parameter>0)//reset the url
            modified_url.setUrl(current_url.toString());
        if(parseUrl(current_parameter))
        {
            //settings ...
            QSettings settings;
            if(settings.value("network/useproxy").toBool())
            {
                    http->setProxy(
                    settings.value("network/sca_host").toString(),
                    settings.value("network/sca_port").toInt(),
                    settings.value("network/sca_name").toString(),
                    settings.value("network/sca_pass").toString()
                    );
            }

            //the request ...
            QHttpRequestHeader header;
            header.setValue("User-agent",settings.value("crawler/user-agent","Firefox 3").toString());
            header.setValue("Host",modified_url.host());
            header.setRequest("GET",modified_url.toString());
            http->setHost(modified_url.host(),modified_url.port(80));
            http->request(header);
        }
        else
        {//go to the next attack
            if(current_parameter<current_url.queryItems().count())
                current_parameter++;//test the next parameter
            else//test next issues
                currentExecutedIssues++;
            if(allExecutedIssues->count()>currentExecutedIssues)
                allExecutedIssues->at(currentExecutedIssues)->execute();
            else
            {
                runScanner::setLog("GET Scan ended\n************************\nPOST Scan Started\n");
                launchAttack(1);//
            }
        }
    }
    else
    {
        currentExecutedIssues++;
        runScanner::setLog("Url rewriting on "+this->current_url.toString()+" we can't execute it\n");
        qDebug()<<"Url rewriting on "<<this->current_url.toString()<<" we can't execute it exploit";
        if(allExecutedIssues->count()>currentExecutedIssues)
            allExecutedIssues->at(currentExecutedIssues)->execute();
    }
}
void issuesExecuter::getExecution() {
    QString executionResult=QString(http->readAll());
    QRegExp rx=issuesDatabase::allIssues->at(id_issue)->getRegExp();
    rx.setCaseSensitivity(Qt::CaseInsensitive);
    rx.setMinimal(true);

    if( rx.indexIn(executionResult) != -1 || executionResult.contains(rx) || rx.exactMatch(executionResult) )
    {
        if(method==0)
            runScanner::setLog("[GET] Issue '"+rx.pattern()+"' Found in : "+this->current_url.toString()+" via "+modified_url.toString()+"\n");
        if(method==1)
            runScanner::setLog("[POST] Issue '"+rx.pattern()+"' Found in : "+this->current_url.toString()+" via "+modified_url.encodedQuery()+"\n");
    }
    if( (method==0 && current_parameter<current_url.queryItems().count()) ||
        (method==1 && current_parameter<current_form->getInput()->size()) )
        current_parameter++;//test the next parameter
    else//test next issues
        currentExecutedIssues++;
    if(currentExecutedIssues<allExecutedIssues->count())
    {
        if(method==0)
            allExecutedIssues->at(currentExecutedIssues)->execute();//go to the next attack
        if(method==1)
            allExecutedIssues->at(currentExecutedIssues)->executePost();//go to the next attack
    }
    else
    {
        qDebug()<<"Ended!!!!!";
        runScanner::setLog("Scan ended\n");
    }
}

bool issuesExecuter::parseUrl(int index) {
	if(!modified_url.hasQuery())
            return false;
        if(index>current_url.queryItems().count())
            return false;
	QList<QPair<QString, QString> > query;
	for(int i=0;i<current_url.queryItems().count();i++)
	{
		QPair<QString,QString> pair;
		pair.first=current_url.queryItems().at(i).first;
                if(index==i)
                    pair.second=issuesDatabase::allIssues->at(id_issue)->getPayload();
                else
                    pair.second=current_url.queryItems().at(i).second;
		query.append(pair);
	}
        modified_url.setQueryItems(query);
	return (modified_url!=current_url);
}

void issuesExecuter::launchAttack(int method) {
    if(method==0)//GET
    {
        for(int i=0;i<UrlCatched::allUrl->count();i++)
		for(int j=0;j<issuesDatabase::allIssues->count();j++)
                        issuesExecuter *ie=new issuesExecuter(i,j,method);
    }
    else if(method==1)//POST
    {
        delete(allExecutedIssues);//delete all ExecutedIssue from last attack
        allExecutedIssues=new QList<issuesExecuter*>;
        for(int i=0;i<FormCatched::allForm->count();i++)
                for(int j=0;j<issuesDatabase::allIssues->count();j++)
                        issuesExecuter *ie=new issuesExecuter(i,j,method);
    }
    //todo make filter (some attack only work against post or get or cookie or ...)
    if(allExecutedIssues->count()>0)
    {
        currentExecutedIssues=0;
        if(method==0)
            allExecutedIssues->at(0)->execute();
        if(method==1)
            allExecutedIssues->at(0)->executePost();
    }
}

/*POST PART*/
bool issuesExecuter::parseForm(int index) {
    if(index>current_form->getInput()->count())
        return false;

    QList<QPair<QString, QString> > query;
    for(int i=0;i<current_form->getInput()->count();i++)
    {
        QPair<QString,QString> pair;
        pair.first=current_form->getInput()->at(i).first;
        if(index==i)
            pair.second=issuesDatabase::allIssues->at(id_issue)->getPayload();
        else
            pair.second=current_form->getInput()->at(i).second;
        query.append(pair);
    }
    modified_url.setQueryItems(query); //we will use the setQueryItems to post data ;)
    return (modified_url!=current_url);//always different ...
}

void issuesExecuter::executePost() {
    if(currentExecutedIssues>allExecutedIssues->count())
    {
        runScanner::setLog("Post scan ended successufly \n");
        return;
    }

    if(FormCatched::allForm->at(base_url)->getInput()>0)
    {//here execution with QHttp object
        http=new QHttp(this);
        connect(http,SIGNAL(done(bool)),this,SLOT(getExecution()));

        if(current_parameter>0)//reset the url
            modified_url.setUrl(current_url.toString());

        if(parseForm(current_parameter))
        {
            //settings ...
            QSettings settings;
            if(settings.value("network/useproxy").toBool())
            {
                http->setProxy(
                settings.value("network/sca_host").toString(),
                settings.value("network/sca_port").toInt(),
                settings.value("network/sca_name").toString(),
                settings.value("network/sca_pass").toString()
                );
            }

            //the request ...
            //qDebug()<<"POST Url : "<<current_url.toString()<<" Parametre : "<<modified_url.encodedQuery();
            QHttpRequestHeader header("POST",modified_url.toString());
            header.setValue("User-agent",settings.value("crawler/user-agent","Firefox 3").toString());
            header.setValue("Host",modified_url.host());
            header.setContentType("application/x-www-form-urlencoded");
            header.setContentLength(modified_url.encodedQuery().length());
            //header.setRequest("POST",current_url.toString());
            http->setHost(modified_url.host(),modified_url.port(80));
            http->request(header,modified_url.encodedQuery());
        }
        else
        {//go to the next attack
            if(current_parameter<current_form->getInput()->count())
                current_parameter++;//test the next parameter
            else//test next issues
                currentExecutedIssues++;
            if(allExecutedIssues->count()>currentExecutedIssues)
                allExecutedIssues->at(currentExecutedIssues)->executePost();
        }
    }
    else
    {
        currentExecutedIssues++;
        runScanner::setLog("Url rewriting on "+this->current_url.toString()+" we can't execute it\n");
        qDebug()<<"Url rewriting on "<<this->current_url.toString()<<" we can't execute it exploit";
        if(allExecutedIssues->count()>currentExecutedIssues)
            allExecutedIssues->at(currentExecutedIssues)->executePost();
    }
}
